#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qfiledialog.h>
#include <qdebug.h>
#include <qstring.h>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    lineMatch=new LineMatch;
    qrcodeDetect=new QrcodeDetect;

}

MainWindow::~MainWindow()
{
    delete ui;


}


bool lineFitLeastSquares(const QQueue<MathPoint> &points, MathPoint &point1Out,MathPoint &point2Out, double &corationCoefficient,
                         double &a_out,double &b_out,double &c_out)
{
//    float *data_x, float *data_y, , vector<float> &vResult
    int data_n=points.size();
    if(data_n < 2)
    {
        return false;
    }
    float A = 0.0;
    float B = 0.0;
    float C = 0.0;
    float D = 0.0;
    float E = 0.0;
    float F = 0.0;

    for (int i=0; i<data_n; i++)
    {
        A += points[i].x * points[i].x;
        B += points[i].x;
        C += points[i].x * points[i].y;
        D += points[i].y;
    }

    // 计算斜率a和截距b
    float a, b, temp = 0;
    if( temp = (data_n*A - B*B) )// 判断分母不为0
    {
        a = (data_n*C - B*D) / temp;
        b = (A*D - B*C) / temp;
    }
    else
    {
        a = 1;
        b = 0;
    }

    // 计算相关系数r
    float Xmean, Ymean;
    Xmean = B / data_n;
    Ymean = D / data_n;

    float tempSumXX = 0.0, tempSumYY = 0.0;
    for (int i=0; i<data_n; i++)
    {
        tempSumXX += (points[i].x - Xmean) * (points[i].x - Xmean);
        tempSumYY += (points[i].y - Ymean) * (points[i].y - Ymean);
        E += (points[i].x - Xmean) * (points[i].y - Ymean);
    }
    F = sqrt(tempSumXX) * sqrt(tempSumYY);

    float r;
    r = E / F;
//    qDebug()<<"直线相干系数"<<r;
    corationCoefficient=r;
    if(fabs(r)<0.001)
    {
        return false;
    }

    point1Out.x=points[0].x;
    point1Out.y=a*point1Out.x+b;

    point2Out.x=points[data_n-1].x;
    point2Out.y=a*point2Out.x+b;

    a_out=a;
    b_out=-1.0;
    c_out=b;

    return true;
}


bool MainWindow::opencvFitLine(QQueue<MathPoint> pointData, MathPoint &point1Out, MathPoint &point2Out,
                               double &corationCoefficient, double &a_out, double &b_out, double &c_out)
{
//    https://blog.csdn.net/eric_e/article/details/79441038
//输出参数的前半部分给出的是直线的方向，而后半部分给出的是直线上的一点（即通常所说的点斜式直线）
//    Mat img(60, 60, CV_8UC1, Scalar(0));
//        std::vector<Point2f> points;
        std::vector<cv::Point> points;
        for(int i=0;i<pointData.size();i++)
        {
           points.push_back(Point(pointData[i].x, pointData[i].y));
        }

        //储存拟合直线的容器
        Vec4f line;
        //直线拟合函数
        fitLine(points, line, CV_DIST_L1, 0, 0.01, 0.01);//87, 45
        double angle=atan2(line[3]-line[1],line[2]-line[0]);
        qDebug()<< "CV_DIST_L1 line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;

        fitLine(points, line, CV_DIST_L2, 0, 0.01, 0.01);//84, 45
        angle=atan2(line[3]-line[1],line[2]-line[0]);
        qDebug()<< "CV_DIST_L2 line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;

//        fitLine(points, line, CV_DIST_C, 0, 0.01, 0.01);
        fitLine(points, line, CV_DIST_L12, 0, 0.01, 0.01);//85, 45
        angle=atan2(line[3]-line[1],line[2]-line[0]);
        qDebug()<< "CV_DIST_L12 line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;

        fitLine(points, line, CV_DIST_FAIR, 0, 0.01, 0.01);//85, 45
        angle=atan2(line[3]-line[1],line[2]-line[0]);
        qDebug()<< "CV_DIST_FAIR line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;

        fitLine(points, line, CV_DIST_WELSCH, 0, 0.01, 0.01);//84, 45
        angle=atan2(line[3]-line[1],line[2]-line[0]);
        qDebug()<< "CV_DIST_WELSCH line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;

        fitLine(points, line, CV_DIST_HUBER, 0, 0.01, 0.01);//84, 45
        angle=atan2(line[3]-line[1],line[2]-line[0]);
        qDebug()<< "CV_DIST_HUBER line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;

        qDebug()<< "1111111111line: pointsize= " <<pointData.size();

        lineFitLeastSquares(pointData, point1Out, point2Out,
                            corationCoefficient, a_out, b_out, c_out);
        angle=atan2(point2Out.y-point1Out.y,point2Out.x-point1Out.x);
        qDebug()<< "my line " <<line[0]<<" "<<line[1]<<" "<<line[2]<<" "<<line[3]<<" "
                <<" angle="<<angle*180/M_PI;




}

//int MainWindow::detectQrcode()
//{

////    作者：gloomyfish
////    来源：CSDN
////    原文：https://blog.csdn.net/jia20003/article/details/77348170

//        /*for (int i = 1; i < 25; i++) {
//                Mat qrcode_image = imread(format("D:/gloomyfish/qrcode/%d.jpg", i));
//                scanAndDetectQRCode(qrcode_image, i);
//            }
//            return 0;
//            */
//            Mat src = imread("D:/gloomyfish/qrcode_99.jpg");
//            if (src.empty()) {
//                printf("could not load image...\n");
//                return -1;
//            }
//            namedWindow("input image", CV_WINDOW_AUTOSIZE);
//            imshow("input image", src);

//            Mat gray, binary;
//            cvtColor(src, gray, COLOR_BGR2GRAY);
//            imwrite("D:/gloomyfish/outimage/qrcode_gray.jpg", gray);

//            threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
//            imwrite("D:/gloomyfish/outimage/qrcode_binary.jpg", binary);

//            // detect rectangle now
//            std::vector<std::vector<Point> > contours;
//            std::vector<Vec4i> hireachy;
//            Moments monents;
//            findContours(binary.clone(), contours, hireachy, RETR_LIST, CHAIN_APPROX_SIMPLE, Point());
//            Mat result = Mat::zeros(src.size(), CV_8UC3);
//            for (size_t t = 0; t < contours.size(); t++) {
//                double area = contourArea(contours[t]);
//                if (area < 100) continue;
//                RotatedRect rect = minAreaRect(contours[t]);
//                // 根据矩形特征进行几何分析
//                float w = rect.size.width;
//                float h = rect.size.height;
//                float rate = min(w, h) / max(w, h);
//                if (rate > 0.85 && w < src.cols/4 && h<src.rows/4) {
//                    printf("angle : %.2f\n", rect.angle);
//                    Mat qr_roi = transformCorner(src, rect);
//                    if (isXCorner(qr_roi) && isYCorner(qr_roi)) {
//                        drawContours(src, contours, static_cast<int>(t), Scalar(0, 0, 255), 2, 8);
//                        imwrite(format("D:/gloomyfish/outimage/contour_%d.jpg", static_cast<int>(t)), qr_roi);
//                        drawContours(result, contours, static_cast<int>(t), Scalar(255, 0, 0), 2, 8);
//                    }
//                }
//            }
//            imshow("result", src);
//            imwrite("D:/gloomyfish/outimage/qrcode_patters.jpg", src);
//            waitKey(0);
//            return 0;


//}



void MainWindow::on_pushButton_clicked()
{
    on_pushButton_setParameter_clicked();
    int size=lineMatch->detectLine(ui->lineEdit_filename->text());

    ui->lineEdit_lineSize->setText(QString::number(size));
}

void MainWindow::on_pushButton_browser_files_clicked()
{
    //定义文件对话框类
       QFileDialog *fileDialog = new QFileDialog(this);
       fileDialog->resize(400,500);
       //定义文件对话框标题
       fileDialog->setWindowTitle(tr("选择文件"));
       //设置默认文件路径
       QString configFile ="/root/图片";
       fileDialog->setDirectory(configFile);
       //设置文件过滤器
       fileDialog->setNameFilter(tr("*(*)"));
       //设置可以选择多个文件,默认为只能选择一个文件QFileDialog::ExistingFiles
       fileDialog->setFileMode(QFileDialog::ExistingFiles);
       //设置视图模式
       fileDialog->setViewMode(QFileDialog::Detail);
       //打印所有选择的文件的路径
       QStringList fileNames;
       if(fileDialog->exec())
       {
           fileNames = fileDialog->selectedFiles();
       }
        qDebug()<<fileNames;
        if(fileNames.size()>0)
        {
            ui->lineEdit_filename->setText(fileNames[0]);
        }
}

void MainWindow::on_pushButton_setParameter_clicked()
{
    double rho=ui->lineEdit_para->text().toDouble();
    double theta=ui->lineEdit_para_2->text().toDouble();
    int threshold=ui->lineEdit_para_3->text().toDouble();
    double minLineLength=ui->lineEdit_para_4->text().toDouble();
    double maxLineGap=ui->lineEdit_para_5->text().toDouble();
    lineMatch->setLineDetectPara(rho,theta,threshold,minLineLength,maxLineGap);
}

void MainWindow::on_pushButton_2_clicked()
{
    on_pushButton_setParameter_clicked();
    double min_angle=ui->lineEdit_vmark_minAngle->text().toDouble();
    double max_angle=ui->lineEdit_vmark_maxAngle->text().toDouble();
    double max_distance=ui->lineEdit_vmark_maxDistance->text().toDouble();
    double vdistanceBias=ui->lineEdit_vmark_distanceBias->text().toDouble();
    double vangleBias=ui->lineEdit_vmark_angleBias->text().toDouble();

    std::vector<double> x_out;
    std::vector<double> y_out;
    std::vector<double> r_out;
    lineMatch->detectVMark_mapFile(ui->lineEdit_filename->text(),min_angle,max_angle,max_distance,vdistanceBias,vangleBias,x_out,y_out,r_out);

    ui->lineEdit_vmark_size->setText(QString::number(x_out.size()));

}

void MainWindow::on_pushButton_browser_files_2_clicked()
{
    MathPoint tmpPoint1;
    tmpPoint1.x=0;
    tmpPoint1.y=0;

    QQueue<MathPoint> pointData;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=6;
    tmpPoint1.y=0;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=1;
    tmpPoint1.y=1;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=2;
    tmpPoint1.y=2;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=3;
    tmpPoint1.y=3;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=4;
    tmpPoint1.y=4;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=5;
    tmpPoint1.y=5;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=6;
    tmpPoint1.y=6;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=7;
    tmpPoint1.y=7;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=8;
    tmpPoint1.y=8;
    pointData.enqueue(tmpPoint1);
    tmpPoint1.x=9;
    tmpPoint1.y=9;
    pointData.enqueue(tmpPoint1);
    MathPoint point1Out;
    MathPoint point2Out;
    double corationCoefficient;
    double a_out;
    double b_out;
    double c_out;
    opencvFitLine(pointData,point1Out,point2Out,corationCoefficient,a_out,b_out,c_out);

}

void MainWindow::on_pushButton_detectQrCode_clicked()
{
    qrcodeDetect->detectQrcode(ui->lineEdit_filename->text());
}
